﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Offset = System.Int32;

namespace EditoneLib
{
    public sealed class ChannelMapping : IEnumerable<MappingInfo>
    {
        public const int All = 0;

        private HashSet<MappingInfo> _mappingSet = new HashSet<MappingInfo>();

        public IEnumerable<int> Channels
        {
            get
            {
                return _mappingSet.Select((info)=>info.Channel).Where(i => i > 0).Distinct();
            }
        }

        public int NumChannels
        {
            get { return Channels.Any() ? Channels.Max() : 1; }
        }

        public HashSet<MappingInfo> this[int channel]
        {
            get { return new HashSet<MappingInfo>(_mappingSet.Where((info)=>info.Channel == channel)); }
        }

        public HashSet<MappingInfo> this[IAudioTrack track]
        {
            get
            {
                return new HashSet<MappingInfo>(_mappingSet.Where((info)=>info.Track == track));
            }
        }

        public IEnumerator<MappingInfo> GetEnumerator()
        {
            return _mappingSet.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public void Map(IAudioTrack track, int offset, int channel, float amount)
        {
            Map(new MappingInfo()
            {
                Amount = amount,
                Track = track,
                Offset = offset,
                Channel = channel
            });
        }

        public void Map(MappingInfo info)
        {
            _mappingSet.Add(info);
        }

        public void Unmap(IAudioTrack track)
        {
            foreach (var info in _mappingSet.Where((info) => info.Track == track))
            {
                _mappingSet.Remove(info);
            };
        }

        public void Unmap(IAudioTrack track, Offset offset)
        {
            foreach (var info in _mappingSet.Where((info)=>info.Track == track && info.Offset == offset))
            {
                _mappingSet.Remove(info);
            };
        }

        public void Unmap(MappingInfo info)
        {
            if (_mappingSet.Contains(info))
            {
                _mappingSet.Remove(info);
            }
        }
    }

    public struct MappingInfo
    {
        public IAudioTrack Track;
        public Offset Offset;
        public float Amount;
        public int Channel;
    }
}